#include "transact.h"
#include "sql_Connector.h"
transact::transact(QDialog *parent )
	: QDialog(parent)
{
	ui.setupUi(this);
	Initialize();
}

transact::transact(vector<vector<string> > &stockDisplay_current,QDialog *parent): QDialog(parent)
{
	stockDisplay_pointer=&stockDisplay_current;
	ui.setupUi(this);
	Initialize();
}

transact::~transact()
{
	
}

/*
	Do initialize stuff here
*/
void transact::Initialize()
{
	ui.transact_res->setText("");
	QObject::connect(ui.transact_table,SIGNAL(cellDoubleClicked(int,int)),this,SLOT(removeEntry(int,int)));
	riskStock.clear();
	int i;
	int size=stockDisplay_pointer->size();
	for (i=0;i<size;i++)
			riskStock.insert(std::pair<string,int>(stockDisplay_pointer->at(i)[colItemID],i));
}

/*
	Cancel current transaction
*/
void transact::on_transact_Cancel_clicked()
{
	this->close();
}

/*
	Add a row to insert new item info
*/
void transact::on_transact_Item_add_clicked()
{
	mergeBarcode();
	ui.transact_table->insertRow(0);
	int col=ui.transact_table->columnCount();
	for (int i=0;i<col;i++)
	{
		ui.transact_table->setItem(0,i,new QTableWidgetItem(""));
	}
}

/*
	Merge duplicate barcode, barcode to consider is the first barcode
	return 
		1 if there is duplicate
		0 if not
*/
int transact::mergeBarcode()
{
	int rowCount=ui.transact_table->rowCount();
	if (rowCount)
	{
		QString barcode=ui.transact_table->item(0,barcod)->text();
		int i;
		int num1,num2;
		for (i=1;i<rowCount;i++)
			if (barcode==ui.transact_table->item(i,barcod)->text())
			{
				
				QString quantity1 = ui.transact_table->item(0,quantit)->text();
				QString quantity2 = ui.transact_table->item(i,quantit)->text();
				if (is_number(quantity1.toStdString())&& is_number(quantity2.toStdString()))
				{
					num1=boost::lexical_cast<int>(quantity1.toStdString());
					num2=boost::lexical_cast<int>(quantity2.toStdString());
					string num=boost::lexical_cast<string>(num1+num2);
					ui.transact_table->item(i,quantit)->setText(QString::fromStdString(num));
				}
				ui.transact_table->removeRow(0);
				return 1;
			}
	}
	return 0;
}

/*
	Submit the transactions to add to database
*/
void transact::on_transact_Submit_clicked()
{
	mergeBarcode();
	bool Alright=true;
	transact_Items.clear();
	vector<string> Item_transact;
	toTransaction.clear();
	vector<vector<string> > tmpVec;
	tmpVec.clear();
	if (check_transact_syntax())
	{
		double transaction_price=0;
		double item_price;
		//Set up SQL CONNECTOR
		sql_Connector *contor=new sql_Connector();
		contor->start_Connect();
		contor->chooseDB("CG3002");
		int i,j,atRisksize;
		QTableWidgetItem *tmp;

		int ro=ui.transact_table->rowCount();
		for (i=0;i<ro;i++)
		{
			tmp=ui.transact_table->item(i,0);

			//Taking the parameters and convert to stdString
			QString barcode = tmp->text();
			string barcod = barcode.toStdString();
			tmp=ui.transact_table->item(i,1);

			QString quantity = tmp->text();
			string quantit = quantity.toStdString();

			tmp=ui.transact_table->item(i,2);
			QString cashier = ui.transact_table->item(0,2)->text();
			string cashie = cashier.toStdString();

			// Get item_price, also check if barcode exists
			item_price=check_barcode(barcod,quantit,i,contor);
			if (item_price < 0)
			{
				Alright=false;
				break;
			}
			transaction_price+=item_price;

			// Check if cashier exists if first row
			if (!i)
			{
				if (!check_cashier(cashie,i,contor))
				{
					Alright=false;
					break;
				}
			}
			else
				ui.transact_table->item(i,cashi)->setText(cashier);


			// Finally insert the new Transactions
			Item_transact.clear();
			Item_transact.push_back(barcod);
			Item_transact.push_back(quantit);
			Item_transact.push_back(cashie);
			toTransaction.push_back(Item_transact);
			//contor->insert_new_Transaction(barcod,quantit,cashi);


			// Update below min stock vector
			assert(stockDisplay_pointer!=NULL);
			if (atRiskItem.size())
			{
				tmpVec.push_back(atRiskItem);
				atRiskItem.clear();
			}
			ostringstream convert;
			convert << transaction_price;
			
			ui.transact_res->setStyleSheet("QLabel { color : green; font: bold 12px; }");
			ui.transact_total_price->setText(QString::fromStdString(convert.str()));
			ui.transact_res->setText("Updated transaction to record successfully, to quit: press X ");
		}

		

		if (Alright==true)
		{
			contor->insert_new_Transaction_list(toTransaction);
			int tmpVecSize=tmpVec.size();
			string inOvector;
			int k;
			for (int z=0;z<tmpVecSize;z++)
			{
				// check the last element, if 1 then the item already in original vector
				inOvector=tmpVec[z][colItemBundleUnit+1];
				tmpVec[z].pop_back();
				if (inOvector=="0")
					stockDisplay_pointer->push_back(tmpVec[z]);
				else
					update_stock_Pointer(tmpVec[z]);
			}
			// Disable all the button
			ui.transact_Item_add->setEnabled(false);
			ui.transact_Submit->setEnabled(false);
			ui.transact_Cancel->setEnabled(false);
		}
		delete contor;
	}
}

bool transact::is_number(const std::string& s)
{
	return !s.empty() && std::find_if(s.begin(), 
        s.end(), [](char c) { return !isdigit(c); }) == s.end();
}

/*
	Support function for on_Transact_submit, check if the value in the cells is not empty or not integer
	Doesn't check if the value is valid or not
	return: 0 if wrong
			1 if right
*/
int transact::check_transact_syntax()
{
	int i;
	int result=1;
	QTableWidgetItem *tmp;
	QColor color=Qt::red;
	
	int ro=ui.transact_table->rowCount();
	for (i=0;i<ro;i++)
	{
		tmp=ui.transact_table->item(i,0);

		//Taking the parameters and convert to stdString
		QString barcode = tmp->text();
		string barcod = barcode.toStdString();
		tmp=ui.transact_table->item(i,1);
		// Check barcode syntax
		if (!is_number(barcod))
		{
			color=Qt::red;
			result=0;
		}
		else
			color=Qt::white;
		ui.transact_table->item(i,0)->setBackgroundColor(color);

		QString quantity = tmp->text();
		string quantit = quantity.toStdString();
		// Check quantity syntax
		if (!is_number(quantit))
		{
			color=Qt::red;
			result=0;
		}
		else
			color=Qt::white;
		ui.transact_table->item(i,1)->setBackgroundColor(color);

		// Check cashierId syntax if only i=0
		if (i==0)
		{
			tmp=ui.transact_table->item(i,2);
			QString cashier = tmp->text();
			string cashi = cashier.toStdString();

			if (!is_number(cashi))
			{
				color=Qt::red;
				result=0;
			}
			else
				color=Qt::white;
			ui.transact_table->item(i,2)->setBackgroundColor(color);
		}

	}

	ui.transact_res->setStyleSheet("QLabel { color : red; font: bold 12px; }");
	if (!result)
		ui.transact_res->setText("Please fill the red cell(s) with correct format");
	else
		ui.transact_res->setText("");

	return result;
}

/*
	Check if the barcode in row "ro" exists with enough quantity and 
	return the total price of the item with the barcode (consider bundle)
	return -1 if wrong
*/
double transact::check_barcode(string barcode,string quantity,int ro,sql_Connector *contor)
{
	ui.transact_res->setStyleSheet("QLabel { color : red; font: bold 12px; }");
	ostringstream convert;
	convert << barcode;
	int bar=atoi(convert.str().c_str());
	convert.str("");
	convert << quantity;
	int quan = atoi(convert.str().c_str());
	convert.str("");
	convert << (ro+1);
	QString cur_row= QString::fromStdString(convert.str());
	Item *tmp=new Item();
	QString result;
	if (contor->search_from_barcode(bar,tmp))
	{
		if (tmp->get_ItemLocalStock()>=quan)
		{
			double price=tmp->get_ItemPrice();
			double total_price;
			int bundle,min_stock,cur_stock;

			// Check if we should discount
			bundle=tmp->get_ItemBundelUnit();
			if (quan>=bundle && bundle!=0)
				price=price*0.9;
			total_price=price*quan;


			//Check if item will <= min_stock
			min_stock=tmp->get_ItemMinStock();
			cur_stock=tmp->get_ItemLocalStock();
			if (cur_stock-quan <= min_stock)
			{
				tmp->set_ItemLocalStock(tmp->get_ItemLocalStock()-quan );
				addAtRiskItem(tmp);
				// We check if the item already in the original vector
				if (cur_stock<=min_stock)
					atRiskItem.push_back("1");
				else
					atRiskItem.push_back("0");
			}

			convert.str("");
			convert<<price;
			result=QString::fromStdString(convert.str());
			ui.transact_table->setItem(ro,3,new QTableWidgetItem(result));
			return total_price;
		}
		else
		{
			result="item in row " + cur_row + " doesn't have enough stock!";
			ui.transact_res->setText(result);
			return -1;
		}
	}
	else
	{
		result="barcode in row " + cur_row + " doesn't exist!";
		ui.transact_res->setText(result);
		return -1;
	}
}

/*
	Return 1 if cashier exists
	Return 0 if no
*/
int transact::check_cashier(string cId, int ro, sql_Connector *contor)
{
	ostringstream convert;
	convert << cId;
	int cashierId=atoi(convert.str().c_str());
	convert.str("");
	convert << (ro+1);
	QString cur_row= QString::fromStdString(convert.str());
	QString result="";
	if (contor->search_cashier_from_cId(cashierId))
	{
		ui.transact_res->setText(result);
		return 1;
	}
	else
	{
		ui.transact_res->setStyleSheet("QLabel { color : red; font: bold 12px; }");
		result="cashier in row " + cur_row + " doesn't exist!";
		ui.transact_res->setText(result);
		return 0;
	}
}

void transact::addAtRiskItem(Item *iI)
{
	if (atRiskItem.size())
		atRiskItem.clear();
	for (int j = colItemID; j <= colItemBundleUnit; j++ ) {
			switch(j) {
			case colItemID:
				atRiskItem.push_back(boost::lexical_cast<string>(iI->get_ItemID()));
				break;
			case colItemName:
				atRiskItem.push_back(boost::lexical_cast<string>(iI->get_ItemName()));
				break;
			case colItemCat:
				atRiskItem.push_back(boost::lexical_cast<string>(iI->get_ItemCategory()));
				break;
			case colItemManu:
				atRiskItem.push_back(boost::lexical_cast<string>(iI->get_ItemManufacturer()));
				break;
			case colItemPrice:
				atRiskItem.push_back(iI->get_ItemPrice_toStr());
				break;
			case colItemLocalStock:
				atRiskItem.push_back(boost::lexical_cast<string>(iI->get_ItemLocalStock()));
				break;
			case colItemMinStock:
				atRiskItem.push_back(boost::lexical_cast<string>(iI->get_ItemMinStock()));
				break;
			case colItemBundleUnit:
				atRiskItem.push_back(boost::lexical_cast<string>(iI->get_ItemBundelUnit()));
				break;
			}	//end switch
		}	// end for j
}

void transact::update_stock_Pointer(vector<string> tmp)
{
	int size=stockDisplay_pointer->size();
	vector<string> tmp2;
	int i=riskStock.find(tmp[colItemID])->second;
		tmp2=stockDisplay_pointer->at(i);
		if (tmp2[colItemID]==tmp[colItemID])
		{
			stockDisplay_pointer->at(i)=tmp;
		}
}

/*
	Check duplicate item when submit
*/
int transact::checkDuplicate(string barcod,int row)
{
	if (transact_Items.find(barcod) != transact_Items.end()) // Exist item
	{
		ui.transact_table->selectRow(row);
		ui.transact_res->setStyleSheet("QLabel { color : red; font: bold 12px; }");
		ui.transact_res->setText(QString::fromStdString("duplicate barcode " + barcod +" !"));
		return 0;
	}
	else
	{
		transact_Items.insert( std::pair<string,int>(barcod,row));
		return  1;
	}
}

void transact::removeEntry(int index,int col)
{
	/*int ro=ui.transact_table->rowCount();
	QTableWidgetItem *tmp;
	tmp=ui.transact_table->item(index,0);*/
	//Taking the parameters and convert to stdString
	/*QString barcode = tmp->text();
	if (!checkDuplicate(barcode.toStdString(),ro-index))
	{
		transact_Items.erase(transact_Items.find(barcode.toStdString()));
	}*/
	ui.transact_res->setText("row remove");
	ui.transact_table->removeRow(index);
}